/**=============================================================================
@file
    qhdsp_hvx.h

@brief
    Header file of QHDSP_HVX library.

Copyright (c) 2020 Qualcomm Technologies Incorporated.
All Rights Reserved. Qualcomm Proprietary and Confidential.
=============================================================================**/

#ifndef _QHDSP_HVX_H
#define _QHDSP_HVX_H

#ifdef __cplusplus
#define restrict __restrict__
extern "C" {
#endif

#include <stdint.h>
#include "qhcomplex.h"
#include "qhl_types.h"

/** @defgroup qhdsp_hvx_library QHDSP_HVX library
 *  @brief QHDSP_HVX library
 *  @{
 */

/** @defgroup qhdsp_hvx_image_processing QHDSP_HVX image processing functions
 *  @brief QHDSP_HVX functions for image processing
 *  @{
 */

/**
 * @brief           Applies a 3x3 kernel to filter an image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[in]       mask - pointer to a 3x3 mask
 * @param[in]       shift - shift amount
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_conv3x3_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, int8_t *mask, uint32_t shift, uint8_t *output, int32_t stride_o);

/**
 * @brief           Applies a 5x5 kernel to filter an image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[in]       mask - pointer to a 5x5 mask
 * @param[in]       shift - shift amount
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_conv5x5_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, int8_t *mask, uint32_t shift, uint8_t *output, int32_t stride_o);

/**
 * @brief           Applies a 7x7 kernel to filter an image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[in]       mask - pointer to a 7x7 mask
 * @param[in]       shift - shift amount
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_conv7x7_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, int8_t *mask, uint32_t shift, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 3x3 dilation of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_dilate3x3_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 5x5 dilation of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_dilate5x5_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 7x7 dilation of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_dilate7x7_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 3x3 erosion of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_erode3x3_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 5x5 erosion of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_erode5x5_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 7x7 erosion of an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_erode7x7_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @brief           Performs 3x3 median filter operation on an input image
 * @param[in]       input - pointer to an input image
 * @param[in]       stride_i - stride of an input image
 * @param[in]       width - width of an input image
 * @param[in]       height - height of an input image
 * @param[out]      output - pointer to an output image
 * @param[in]       stride_o - stride of output image
 * @note
 *                  - Assumptions:
 *                                  1. input - has to be aligned to 128 bytes
 *                                  2. stride_i - has to be modulo of 128
 *                                  3. width - has to be modulo of 128
 *                                  4. output - has to be aligned to 128 bytes
 *                                  5. stride_o - has to be modulo of 128
 */

int32_t qhdsp_hvx_median3x3_ab(uint8_t *input, int32_t stride_i, uint32_t width, uint32_t height, uint8_t *output, int32_t stride_o);

/**
 * @}
 */

/** @defgroup qhdsp_hvx_lms_functions QHDSP_HVX LMS functions
 *  @brief QHDSP_HVX functions for LMS
 *  @{
 */

/**
 * @brief           Performs adaptive filter with least mean square (LMS) algorithm
 * @param[in]       input  - pointer to 16-bit input samples
 * @param[in]       ydes   - pointer to 16-bit desired outputs
 * @param[in]       rate   - adaptive rate
 * @param[in]       taps   - number of filter taps
 * @param[in,out]   states - pointer to 16-bit filter states buffer
 * @param[in,out]   coeffs - pointer to 16-bit filter coefficients
 * @param[out]      error  - 16-bit error buffer
 * @param[out]      output - 16-bit output buffer
 * @param[in]       length - length of input/output/error data
 * @note
 *                  - Assumptions:
 *                                  1. states - has to be taps size
 *                                  2. states - has to be aligned to 128 bytes
 *                                  3. coeffs - has to be taps size
 *                                  4. coeffs - has to be aligned to 128 bytes
 *                                  5. all values are in Q15 format
 */

int16_t qhdsp_hvx_lms_ah(int16_t *input, int16_t *ydes, int16_t rate, uint32_t taps, int16_t *states, int16_t *coeffs, int16_t *error, int16_t *output, uint32_t length);

/**
 * @brief           Performs adaptive filter with least mean square (LMS) algorithm
 * @param[in]       input  - pointer to 32-bit input samples
 * @param[in]       ydes   - pointer to 32-bit desired outputs
 * @param[in]       rate   - adaptive rate
 * @param[in]       taps   - number of filter taps
 * @param[in,out]   states - pointer to 32-bit filter states buffer
 * @param[in,out]   coeffs - pointer to 32-bit filter coefficients
 * @param[out]      error  - 32-bit error buffer
 * @param[out]      output - 32-bit output buffer
 * @param[in]       length - length of input/output/error data
 * @note
 *                  - Assumptions:
 *                                  1. states - has to be taps size
 *                                  2. states - has to be aligned to 128 bytes
 *                                  3. coeffs - has to be taps size
 *                                  4. coeffs - has to be aligned to 128 bytes
 *                                  5. all values are in Q31 format
 */

int16_t qhdsp_hvx_lms_aw(int32_t *input, int32_t *ydes, int32_t rate, uint32_t taps, int32_t *states, int32_t *coeffs, int32_t *error, int32_t *output, uint32_t length);

/**
 * @brief           Performs adaptive filter with least mean square (LMS) algorithm
 * @param[in]       input  - pointer to 32-bit float input samples
 * @param[in]       ydes   - pointer to 32-bit float desired outputs
 * @param[in]       rate   - adaptive rate
 * @param[in]       taps   - number of filter taps
 * @param[in,out]   states - pointer to 32-bit float filter states buffer
 * @param[in,out]   coeffs - pointer to 32-bit float filter coefficients
 * @param[out]      error  - 32-bit float error buffer
 * @param[out]      output - 32-bit float output buffer
 * @param[in]       length - length of input/output/error data
 * @note
 *                  - Assumptions:
 *                                  1. states - has to be taps size
 *                                  2. states - has to be aligned to 128 bytes
 *                                  3. coeffs - has to be taps size
 *                                  4. coeffs - has to be aligned to 128 bytes
 */

int16_t qhdsp_hvx_lms_af(float *input, float *ydes, float rate, uint32_t taps, float *states, float *coeffs, float *error, float *output, uint32_t length);

/**
 * @brief           Performs adaptive filter with least mean square (LMS) algorithm
 * @param[in]       input  - pointer to 16-bit float input samples
 * @param[in]       ydes   - pointer to 16-bit float desired outputs
 * @param[in]       rate   - adaptive rate
 * @param[in]       taps   - number of filter taps
 * @param[in,out]   states - pointer to 16-bit float filter states buffer
 * @param[in,out]   coeffs - pointer to 16-bit float filter coefficients
 * @param[out]      error  - 16-bit float error buffer
 * @param[out]      output - 16-bit float output buffer
 * @param[in]       length - length of input/output/error data
 * @note
 *                  - Assumptions:
 *                                  1. states - has to be taps size
 *                                  2. states - has to be aligned to 128 bytes
 *                                  3. coeffs - has to be taps size
 *                                  4. coeffs - has to be aligned to 128 bytes
 */

int16_t qhdsp_hvx_lms_ahf(__fp16 *input, __fp16 *ydes, __fp16 *rate, uint32_t taps, __fp16 *states,
                          __fp16 *coeffs, __fp16 *error, __fp16 *output, uint32_t length);

/**
 * @}
 */

 /** @defgroup qhdsp_hvx_fft_functions QHDSP_HVX FFT functions
  *  @brief QHDSP_HVX functions for FFT/IFFT
  *  @{
  */

/** @defgroup qhdsp_hvx_real_fft_routines QHDSP_HVX real FFT functions
 *  @brief QHDSP_HVX functions for FFT routines on real numbers
 *  @{
 */

/**
 * @brief           [HVX] Real 1D 8x32 2^N fixed-point FFT
 * @param[in]       input - input samples (unsigned 8-bit)
 * @param[in]       N - number of points on which FFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex FFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - FFT output buffer (signed 32-bit complex)
 * @note
 *                  - Scale factor: 1/N
 *                  - input format Q7, output format Q<log2(N)>.<31-log2(N)>; example: N=128 -> log2(N)=7 -> output format Q7.24
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_fft_gen_twiddles_real_ach() function
 *                                  3. N is power of 2 and N>=128
 */
int32_t qhdsp_hvx_acw_r1dfft_aub(const uint8_t *input, uint32_t N, const int32_t *w1, const int32_t *w2, int64_t *output);

/**
 * @brief           [HVX] Real 2D (NxN) 8x32 2^N fixed-point FFT
 * @param[in]       input - input samples (unsigned 8-bit)
 * @param[in]       N - number of points (of both dimensions) on which FFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex FFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - FFT output buffer (signed 32-bit complex)
 * @note
 *                  - Scale factor: 1/N^2
 *                  - input format Q7, output format Q<2*log2(N)>.<31-2*log2(N)>; example: N=128 -> 2*log2(N)=7 -> output format Q14.17
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_ach() function
 *                                  3. N is power of 2 and N>=128
 *                                  4. 2D FFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_acw_r2dfft_aub(const uint8_t *input, uint32_t N, const int32_t *w1, const int32_t *w2, int64_t *output);

/**
 * @brief           [HVX] Real 1D 32x8 2^N fixed-point IFFT
 * @param[in]       input - input values (signed 32-bit complex)
 * @param[in]       N - number of points on which IFFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex IFFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - IFFT output buffer (unsigned 8-bit)
 * @note
 *                  - input format Q<log2(N)>.<31-log2(N)>; example: N=128 -> log2(N)=7 -> input format Q7.24, output format Q7
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_fft_gen_twiddles_real_ach() function
 *                                  3. N is power of 2 and N>=128
 */
int32_t qhdsp_hvx_aub_r1difft_acw(const int64_t *input, uint32_t N, const int32_t *w1, const int32_t *w2, uint8_t *output);

/**
 * @brief           [HVX] Real 2D (NxN) 32x8 2^N fixed-point IFFT
 * @param[in]       input - input values (signed 32-bit complex)
 * @param[in]       N - number of points (of both dimensions) on which IFFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex IFFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - IFFT output buffer (unsigned 8-bit)
 * @note
 *                  - input format Q<2*log2(N)>.<31-2*log2(N)>; example: N=128 -> 2*log2(N)=7 -> input format Q14.17, output format Q7
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_ach() function
 *                                  3. N is power of 2 and N>=128
 *                                  4. 2D IFFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_aub_r2difft_acw(const int64_t *input, uint32_t N, const int32_t *w1, const int32_t *w2, uint8_t *output);

/**
 * @brief           [HVX]   Real 1D 2^N single precision float point FFT
 * @param[in]       input   input samples in time domain
 * @param[in]       N       number of points on which FFT is performed
 * @param[in]       Wt1     twiddle factors - for N/2-point complex FFT
 * @param[in]       Wt2     twiddle factors - for last stage
 * @param[out]      output  FFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_fft_gen_twiddles_real_acf() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_r1dfft_af(const float* input, uint32_t N, const float complex *Wt1, const float complex *Wt2, float complex *output);

/**
 * @brief           [HVX]   Real 1D 2^N single precision float point IFFT
 * @param[in]       input   input samples in frequency domain
 * @param[in]       N       number of samples on which IFFT is performed
 * @param[in]       Wt1     twiddle factors - for N/2-point complex IFFT
 * @param[in]       Wt2     twiddle factors - for last stage
 * @param[out]      output  IFFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_fft_gen_twiddles_real_acf() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_r1difft_af(const float complex *input, uint32_t N, const float complex *Wt1, const float complex *Wt2, float *output);

/**
 * @brief           [HVX] Real 2D (NxN) 2^N single precision float point FFT
 * @param[in]       input - input samples
 * @param[in]       N - number of points (of both dimensions) on which FFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex FFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - FFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_acf() function
 *                                  3. N is power of 2 and N>=64
 *                                  4. 2D FFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_r2dfft_af(const float *input, uint32_t N, const float complex *w1, const float complex *w2, float complex *output);

/**
 * @brief           [HVX] Real 2D (NxN) 2^N single precision float point IFFT
 * @param[in]       input - input samples
 * @param[in]       N - number of points (of both dimensions) on which IFFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex IFFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - IFFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_acf() function
 *                                  3. N is power of 2 and N>=64
 *                                  4. 2D IFFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_r2difft_af(const float complex *input, uint32_t N, const float complex *w1, const float complex *w2, float *output);

/**
 * @brief           [HVX] Real 1D 2^N half precision float point FFT
 * @param[in]       input - input samples in time domain (real)
 * @param[in]       N - number of samples on which FFT is performed
 * @param[in]       Wt1 - twiddle factors - for N/2-point complex FFT
 * @param[in]       Wt2 - twiddle factors - for last stage
 * @param[out]      output - FFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, Wt1, Wt2, output - buffer aligned by 128bytes
 *                                  2. Wt1, Wt2 - generated with qhdsp_hvx_fft_gen_twiddles_real_achf() function
 *                                  3. N is power of 2 and N>=128
 */
int32_t qhdsp_hvx_r1dfft_ahf(const __fp16* input, uint32_t N, const qhl_cfloat16_t *Wt1, const qhl_cfloat16_t *Wt2, qhl_cfloat16_t *output);

/**
 * @brief           [HVX] Real 1D 2^N half precision float point IFFT
 * @param[in]       input - input samples in frequency domain
 * @param[in]       N - number of samples on which IFFT is performed
 * @param[in]       Wt1 - twiddle factors - for N/2-point complex IFFT
 * @param[in]       Wt2 - twiddle factors - for last stage
 * @param[out]      output - IFFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_fft_gen_twiddles_real_achf() function
 *                                  3. N is power of 2 and N>=128
 */
int32_t qhdsp_hvx_r1difft_ahf(const qhl_cfloat16_t *input, uint32_t N, const qhl_cfloat16_t *Wt1, const qhl_cfloat16_t *Wt2, __fp16 *output);

/**
 * @brief           [HVX] Real 2D (NxN) 2^N half precision float point FFT
 * @param[in]       input - input samples
 * @param[in]       N - number of points (of both dimensions) on which FFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex FFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - FFT output buffer
 * @param[in]       scale_factor - since output values of FFT function can have large range (example: if inputs are in range
 *                  from -1.0 to 1.0 for 128x128 FFT outputs can go up to 16384.0 = pow(2,log2(128)+log2(128)) ) scale_factor
 *                  should be used to multiply (scale down) inputs before applying 2D FFT. This way FFT outputs will be scaled
 *                  down by the same value as input was scaled down, but if properly set, FFT outputs won't get to +/-INF value
 *                  (for IEEE half precision float point every value above 65519 is INF). If scaling down is not needed, simply
 *                  pass 1.0 value in HF (0x3c00) as input parameter.
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_achf() function
 *                                  3. N is power of 2 and N>=64
 *                                  4. 2D FFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_r2dfft_ahf(const __fp16 *input, uint32_t N, const qhl_cfloat16_t *w1, const qhl_cfloat16_t *w2, qhl_cfloat16_t *output, const __fp16 *scale_factor);

/**
 * @brief           [HVX] Real 2D (NxN) 2^N half precision float point IFFT
 * @param[in]       input - input samples
 * @param[in]       N - number of points (of both dimensions) on which IFFT is performed
 * @param[in]       w1 - twiddle factors - for N/2-point complex IFFT
 * @param[in]       w2 - twiddle factors - for last stage
 * @param[out]      output - IFFT output buffer
 * @param[in]       scale_factor - if FFT inputs were scaled down, this parameter is used to scale up IFFT outputs (by reciprocal
 *                  value from the one used in FFT function). If scaling down wasn't done in FFT function, simply pass 1.0 value
 *                  in HF (0x3c00) as input parameter.
 * @note
 *                  - Assumptions:
 *                                  1. input, w1, w2, output - buffer aligned by 128bytes
 *                                  2. w1, w2 - generated with qhdsp_hvx_2D_fft_gen_twiddles_real_achf() function
 *                                  3. N is power of 2 and N>=64
 *                                  4. 2D IFFT assumes width=height=stride -> N
 */
int32_t qhdsp_hvx_r2difft_ahf(const qhl_cfloat16_t *input, uint32_t N, const qhl_cfloat16_t *w1, const qhl_cfloat16_t *w2, __fp16 *output, const __fp16 *scale_factor);

/**
  * @}
  */

/** @defgroup qhdsp_hvx_complex_fft_routines QHDSP_HVX complex FFT functions
 *  @brief QHDSP_HVX functions for FFT routines on complex numbers
 *  @{
 */

/**
 * @brief           [HVX] Complex 1D 8x32 2^N fixed-point FFT
 * @param[in]       input - input samples (unsigned 8-bit complex)
 * @param[in]       N - number of points on which FFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - FFT output buffer (signed 32-bit complex)
 * @note
 *                  - Scale factor: 1/N
 *                  - input format Q7, output format Q<log2(N)>.<31-log2(N)>; example: N=128 -> log2(N)=7 -> output format Q7.24
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_ach() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_acw_c1dfft_acub(const uint16_t *input, uint32_t N, const int32_t *w, int64_t *output);

/**
 * @brief           [HVX] Complex 1D 32x8 2^N fixed-point IFFT
 * @param[in]       input - input values (signed 32-bit complex)
 * @param[in]       N - number of points on which IFFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - IFFT output buffer (unsigned 8-bit complex)
 * @note
 *                  - input format Q<log2(N)>.<31-log2(N)>; example: N=128 -> log2(N)=7 -> input format Q7.24, output format Q7
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_ach() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_acub_c1difft_acw(const int64_t *input, uint32_t N, const int32_t *w, int16_t *output);

/**
 * @brief           [HVX] Complex 1D 2^N single precision float point FFT
 * @param[in]       input - input samples in time domain (complex)
 * @param[in]       N - number of samples on which FFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - FFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_acf() function
 *                                  3. N is power of 2 and N>=32
 */
int32_t qhdsp_hvx_c1dfft_af(const float complex *input, uint32_t N, const float complex *w, float complex *output);

/**
 * @brief           [HVX] Complex 1D 2^N single precision float point IFFT
 * @param[in]       input - input samples in frequency domain (complex)
 * @param[in]       N - number of samples on which IFFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - IFFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_acf() function
 *                                  3. N is power of 2 and N>=32
 */
int32_t qhdsp_hvx_c1difft_af(const float complex *input, uint32_t N, const float complex *w, float complex *output);

/**
 * @brief           [HVX] Complex 1D 2^N half precision float point FFT
 * @param[in]       input - input samples in time domain (complex)
 * @param[in]       N - number of samples on which FFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - FFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_achf() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_c1dfft_ahf(const qhl_cfloat16_t *input, uint32_t N, const qhl_cfloat16_t *w, qhl_cfloat16_t *output);

 /**
 * @brief           [HVX] Complex 1D 2^N half precision float point IFFT
 * @param[in]       input - input samples in frequency domain (complex)
 * @param[in]       N - number of samples on which IFFT is performed
 * @param[in]       w - twiddle factors
 * @param[out]      output - IFFT output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, w, output - buffer aligned by 128bytes
 *                                  2. w - generated with qhdsp_hvx_fft_gen_twiddles_complex_achf() function
 *                                  3. N is power of 2 and N>=64
 */
int32_t qhdsp_hvx_c1difft_ahf(const qhl_cfloat16_t *input, uint32_t N, const qhl_cfloat16_t *w, qhl_cfloat16_t *output);

 /**
   * @}
   */

 /** @defgroup qhdsp_hvx_filters QHDSP_HVX 1D block FIR functions
  *  @brief QHDSP_HVX functions for 1D block FIR
  *  @{
  */

 /**
 * @brief           [HVX] 1D FIR
 * @param[in]       input - input buffer
 * @param[in]       coefs - coefficient buffer
 * @param[in]       taps - number of coefficients
 * @param[in]       length - number of output samples
 * @param[out]      output - output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, coefs and output should be aligned to 128 bytes.
 *                                  2. taps should be multiples of 32, zero-pad the coefficients if necessary
 *                                  3. length should be larger than taps.
 *                                  4. coefs are expected to be stored in reversed order.
 */
int32_t qhdsp_hvx_bkfir_af(const float *input, const float *coefs, uint32_t taps, uint32_t length, float *output);

/**
 * @brief           [HVX] 1D FIR
 * @param[in]       input  - input buffer
 * @param[in]       coeffs - coefficient buffer
 * @param[in]       taps   - number of coefficients
 * @param[in]       length - number of output samples
 * @param[out]      output - output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, coeffs, buffer and output should be aligned to 128 bytes.
 *                                  2. taps should be multiples of 64, zero-pad the coefficients if necessary
 *                                  3. length should be larger than taps.
 *                                  4. coeffs are pre-reversed before the call.
 *                                  5. All input and output are assumed to be in Q15 format.
 */

int32_t qhdsp_hvx_bkfir_ah(const int16_t *input, const int16_t *coeffs, uint32_t taps, uint32_t length, int16_t *output);

/**
 * @brief           [HVX] 1D FIR
 * @param[in]       input  - input buffer
 * @param[in]       coeffs - coefficient buffer
 * @param[in]       taps   - number of coefficients
 * @param[in]       length - number of output samples
 * @param[out]      output - output buffer
 * @note
 *                  - Assumptions:
 *                                  1. input, coeffs and output should be aligned to 128 bytes.
 *                                  2. taps should be multiples of 32, zero-pad the coefficients if necessary
 *                                  3. length should be larger than taps.
 *                                  4. coeffs are pre-reversed before the call.
 *                                  5. All input and output are assumed to be in Q31 format.
 */

int32_t qhdsp_hvx_bkfir_aw(const int32_t *input, const int32_t *coeffs, uint32_t taps, uint32_t length, int32_t *output);

/**
 * @brief           [HVX] Sparse Submanifold Convolution scatter operation, calculates ouput values for inputs and scatter accumulates
 *                  in memory.
 * @param[in]       input_idxs    - input indexes(x1,y1,x2,y2,.....)
 * @param[in]       input_idxs_sz - number of pixels
 * @param[in]       input_vals    - pixel values
 * @param[in]       width         - width of image
 * @param[in]       height        - height of image
 * @param[in]       mask          - convolution kernel
 * @param[in]       mask_size     - convolution kernel size
 * @param[in]       scratchpad    - scratch pad memory for scatter-gather operations(this must be from VTCM)
 * @param[in]       scratchpad_sz - size of scratchpad memory in bytes
 *
 * @note
 *                  - Assumptions:
 *                                  1. The input indices fits into zero-indexed (scratchpad_sz-128) bytes. For example, if the scratchpad
 *                                     size is 10000 bytes, then for 2-byte pixel values and zero-indexed input image, total
 *                                     number of pixels must not cross (5000-64).
 *                                  2. All the buffers passed to function are 128-byte aligned.
 *                                  3. This will fill VTCM passed, with ouput values. User is expected to call qhdsp_hvx_sparse_conv_gather_ah
 *                                     after this operation to get output in buffer.
 */
int32_t qhdsp_hvx_sparse_conv_scatter_ah(uint16_t *restrict  input_idxs, uint32_t input_idxs_sz, int16_t *restrict input_vals,
                                         uint32_t width, uint32_t height, int16_t *restrict mask, int32_t mask_size,
                                         void* scratchpad, uint32_t scratchpad_sz);

/**
 * @brief           [HVX] Sparse Submanifold Convolution gather operation, gathers output values for indices mentioned by input_idxs in output.
 * @param[in]       input_idxs    - input indexes(x1,y1,x2,y2,.....)
 * @param[in]       input_idxs_sz - number of pixels
 * @param[in]       input_vals    - pixel values
 * @param[in]       width         - width of image
 * @param[in]       mask_size     - convolution kernel size
 * @param[in]       scratchpad    - scratch pad memory for scatter-gather operations(this must be from VTCM)
 * @param[in]       scratchpad_sz - size of scratchpad memory in bytes
 *
 * @param[out]      output_val - output buffer
 * @note
 *                  - Assumptions:
 *                                  1. The input indices fits into zero-indexed (scratchpad_sz-128) bytes. For example, if the scratchpad
 *                                     size is 10000 bytes, then for 2-byte pixel values and zero-indexed input image, total
 *                                     number of pixels must not cross (5000-64).
 *                                  2. All the buffers passed to function are 128-byte aligned.
 *                                  3. qhdsp_hvx_sparse_conv_scatter_ah is called before and scratchpad already contains outputs.
 */
int32_t qhdsp_hvx_sparse_conv_gather_ah(uint16_t *restrict  input_idxs, uint32_t input_idxs_sz, uint32_t width, uint32_t mask_size,
                                        int32_t *restrict output_vals, void* scratchpad, uint32_t scratchpad_sz);

/**
 * @brief           [HVX] Sparse Submanifold Convolution
 *                  in memory.
 * @param[in]       input_idxs    - input indexes(x1,y1,x2,y2,.....)
 * @param[in]       input_idxs_sz - number of pixels
 * @param[in]       input_vals    - pixel values
 * @param[in]       width         - width of image
 * @param[in]       height        - height of image
 * @param[in]       mask          - convolution kernel
 * @param[in]       mask_size     - convolution kernel size
 * @param[in]       scratchpad    - scratch pad memory for scatter-gather operations(this must be from VTCM)
 * @param[in]       scratchpad_sz - size of scratchpad memory in bytes
 *
 * @param[out]      output_vals - output buffer
 *
 * @note
 *                  - Assumptions:
 *                                  1. The input indices fits into zero-indexed (scratchpad_sz-128) bytes. For example, if the scratchpad
 *                                     size is 10000 bytes, then for 2-byte pixel values and zero-indexed input image, total
 *                                     number of pixels must not cross (5000-64).
 *                                  2. All the buffers passed to function are 128-byte aligned.
 */
int32_t qhdsp_hvx_sparse_conv_ah(uint16_t *restrict input_idxs, uint32_t input_idxs_sz, int16_t *restrict input_vals, uint32_t width,
                                 uint32_t height, int16_t *restrict mask, int32_t mask_size, int32_t *restrict output_vals, void *scratchpad,
                                 uint32_t scratchpad_sz);
/**
 * @}
 */

/**
 * @}
 */

 /**
  * @}
  */

#ifdef __cplusplus
}
#endif

#endif /* _QHDSP_HVX_H */
